﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TransportAbstractionLibrary.Common;
using System.Net;
using System.Net.Sockets;
using System.Diagnostics;

namespace TransportAbstractionLibrary.UDP
{
    public abstract partial class UDPServer
    {
        SocketEventArgs readingEventArgs;
        object readingLock;

        private void InitializeRead()
        {
            readingLock = new object();
            readingEventArgs = bufferManager.CheckOut();
            readingEventArgs.Initialize(this, EventArgsMode.Read);
        }

        private void HandleData()
        {
            byte[] data;
            data = readingEventArgs.GetRecivedData();
            lock (connectionListLocker)
            {
                if (readingEventArgs.RemoteEndPoint.GetType() == typeof(IPEndPoint))
                {
                    IPEndPoint endPoint = (IPEndPoint)readingEventArgs.RemoteEndPoint;
                    if (endPoint.Address == IPAddress.Any && data.Length == 0)
                    {
                        Trace.WriteLine("Closing udp listener");
                        //This is a signal that the UDP listener is closing
                        return;
                    }
                }
                for (int i = 0; i < connectionList.Count; i++)
                {
                    if (connectionList[i].EndPoint == readingEventArgs.RemoteEndPoint)
                    {
                        if (zeroIsDisconnect && data.Length == 0)
                        {
                            Disconnect(connectionList[i]);
                            return;
                        }
                        connectionList[i].ReceiveData(data);
                        Receive();
                        return;
                    }
                }
                UDPConnection connection = new UDPConnection(this, (IPEndPoint)readingEventArgs.RemoteEndPoint);
                connectionList.Add(connection);
                InboundConnection(connection);
                connection.Initialize();

                if (zeroIsDisconnect && data.Length == 0)
                {
                    Disconnect(connection);
                    return;
                }

                connection.ReceiveData(data);
                //StartRead();
            }
        }

        private void Receive()
        {
            lock (readingLock)
            {
                readingEventArgs.RemoteEndPoint = new IPEndPoint(IPAddress.Any, port);
                readingEventArgs.SocketFlags = SocketFlags.None;
                while (!socket.ReceiveFromAsync(readingEventArgs))
                {
                    HandleData();
                }
            }
        }

        protected abstract void InboundConnection(IProtocolLowerLayer connection);

        void IAsyncHost.OnRecived(SocketEventArgs args)
        {
            if (args.SocketFlags != SocketFlags.None)
            {
                throw new ArgumentException(null, "SocketFlags are not None!, SocketFlags: " + args.SocketFlags.ToString());
            }
            HandleData();
            Receive();
        }
    }
}
